package pools;

// Uses parity of m bit blocks from source to extract a random bit
public class BasicMixingPool extends Pool {

	public static final int NUM_QUASI_RANDOM = 128;
	public static final int NUM_SOURCE = 21; // log2(NUM_QUASI_RANDOM) * iterative_log2(NUM_QUASI_RANDOM)
	
	private volatile int nextQRBits = 0;
	private volatile int nextQRBitPosition = 0;
	private volatile int numberOfOnesForCurrentQRBit = 0;
	private volatile int numberOfBitsForCurrentQRBit = 0;
	
	// Converts a 21 bit block into one random bit
	// Rather than storing multiple integers until I have 21 of them and XORing all together,
	// I am counting 1s as they come in and restarting the count every 21 bits.
	// Neither method truly represents using NUM_SOURCE sources; I opted for this method as
	// I didn't want a string of 21 negative numbers to force a '1' or 21 positive numbers to force a '0'
	public synchronized void add(int nextInt) {
		int mask = 0x80000000;
		for(int i = 0; i < 32; i++){
			boolean isOne = (mask  & nextInt) != 0;
			mask = mask >>> 1;
			numberOfBitsForCurrentQRBit++;
			if(isOne){
				numberOfOnesForCurrentQRBit++;
			}
			if(numberOfBitsForCurrentQRBit == NUM_SOURCE){
				finishCurrentQRBit();
			}
		}
	}

	private void finishCurrentQRBit() {
		int nextQRBit = numberOfOnesForCurrentQRBit % 2 == 0 ? 0 : 1;
		nextQRBit = nextQRBit << nextQRBitPosition++;
		nextQRBits = nextQRBits | nextQRBit;
		if(nextQRBitPosition == 8){
			addToBuffer((byte)nextQRBits);
			nextQRBits = 0;
			nextQRBitPosition = 0;
		}
		numberOfOnesForCurrentQRBit = 0;
		numberOfBitsForCurrentQRBit = 0;
	}

	public String getPoolName() {
		return "Basic Mixing Pool";
	}
	
}
